#include <QtCore/QSocketNotifier>
#include <QtEndian>

#include "bonjourserviceregister.h"


BonjourServiceRegister::~BonjourServiceRegister()
{
	// Destroy the dns reference if it exists.
	if (dnssref)
	{
		DNSServiceRefDeallocate(dnssref);

		dnssref = 0;
	}
}

/** Register a service with Bonjour. */
void BonjourServiceRegister::registerService(const BonjourRecord &record, quint16 servicePort)
{
	// We can't register the same service twice, dumb dumb.
	if (dnssref)
	{
		qWarning("Warning: Already registered a service for this object, aborting new register");

		return;
	}

	// Should execute for x86 etc to convert service port into big endian.
	servicePort = qToLittleEndian(servicePort);

	DNSServiceErrorType err = DNSServiceRegister(&dnssref, 0, 0,
						     record.getServiceName().toUtf8()
						     .constData(), record.getRegisteredType()
						     .toUtf8().constData(), record
						     .getReplyDomain().isEmpty() ? 0
							     : record.getReplyDomain()
							     .toUtf8().constData(), 0,
							     servicePort, 0, 0,
							     bonjourRegisterService, this);

	if (err != kDNSServiceErr_NoError)
		emit error(err);

	else
	{
		int sockfd = DNSServiceRefSockFD(dnssref);

		if (sockfd == -1)
			emit error(kDNSServiceErr_Invalid);

		else
		{
			bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
			connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead()));
		}
	}
}

void BonjourServiceRegister::bonjourSocketReadyRead()
{
	DNSServiceErrorType err = DNSServiceProcessResult(dnssref);

	if (err != kDNSServiceErr_NoError)
		emit error(err);
}

/** Register a Bonjour service. Should only be called by Bonjour itself. */
void BonjourServiceRegister::bonjourRegisterService(DNSServiceRef, DNSServiceFlags,
						    DNSServiceErrorType errorCode, const char *name,
						    const char *regtype, const char *domain,
						    void *data)
{
	BonjourServiceRegister *serviceRegister = static_cast<BonjourServiceRegister *>(data);

	if (errorCode != kDNSServiceErr_NoError)
		emit serviceRegister->error(errorCode);

	else
	{
		serviceRegister->finalRecord = BonjourRecord(name, regtype, domain);

		emit serviceRegister->serviceRegistered(serviceRegister->finalRecord);
	}
}
